package ntd.util;

import cn.hutool.core.lang.Console;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.function.Function;

/**
 * 代理工具类
 */
public class UtilProxy {

    public static <T> T getProxyInstance(T obj, Function<Object[], Object> beforeFunction, Function<Object, Object> afterFunction) {
        ClassLoader loader = obj.getClass().getClassLoader(); //被代理对象的类加载器
        Class<?>[] interfaces = obj.getClass().getInterfaces(); //被代理对象实现的接口
        InvocationHandler h = new InvocationHandler() {  //方法执行器 当调用真实对象所实现的接口的方法时(真实对象的非接口方法是不能被代理的)就会执行invoke方法
            /**
             * proxy 代理对象 是给jdk使用的 自己不需要去动它
             * method 是被代理对象将要被执行的方法
             * args 是方法的参数
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Console.log("代理方法执行之前。。。");  //调用方法前织入的逻辑
                if (beforeFunction != null) {
                    beforeFunction.apply(args);
                }
                Object result = method.invoke(obj, args);  //利用反射执行对应的方法
                Console.log("代理方法执行之后。。。"); //调用方法后织入的逻辑
                if (afterFunction != null) {
                    afterFunction.apply(result);
                }
                return result; //返回方法的执行结果
            }
        };
        //生成代理对象并返回
        return (T) Proxy.newProxyInstance(loader, interfaces, h);
    }

    /**
     * 获取代理对象 入参为真实对象所实现的接口 jdk的动态代理只能是代理接口 无法做到基于类的动态代理
     *
     * @param obj
     * @return
     */
    public static <T> T getProxyInstance(T obj) {
        return getProxyInstance(obj, null, null);
    }
}
